為了今天要用 async 執行非同步取得咖啡廳資料,所以昨天先做了簡單的實驗,現在直接來改寫程式碼吧~~
binding.button.setOnClickListener {
    // 這個 Scope 即是在 Android Main Thread 上啟動 coroutine
    lifecycleScope.launch(Dispatchers.Main) {
        try {
            binding.progressbar.visibility = View.VISIBLE
            // 等待非同步執行結果
            val deferredResult = fetchCoffeeShopDataByAsync().await()
            // 更新畫面
            binding.textView.text = deferredResult
            binding.progressbar.visibility = View.GONE
        }
        catch (e: CoffeeShopsRefreshError) {
            binding.textView.text = "Request failed \nmessage: ${e.message}"
            binding.progressbar.visibility = View.GONE
        }
    }
}
接著來看看使用 async 在 IO 執行緒上啟動 coroutine 執行非同步任務 fetchCoffeeShopDataByAsync() :
private fun fetchCoffeeShopDataByAsync(): Deferred<String?> {
    return lifecycleScope.async(Dispatchers.IO) {
        // 創建一個 OkHttpClient 實例
        val client = OkHttpClient()
        // 設置要發送的 HTTP 請求
        val request = Request.Builder()
            .url("http://cafenomad.tw/api/v1.2/cafes/taipei")
            .build()
        val response = try {
            // 使用 OkHttpClient 發送同步請求
            client.newCall(request).execute()
        }
        catch (cause: IOException) {
            throw CoffeeShopsRefreshError("Unable to refresh data", cause)
        }
        if (!response.isSuccessful) {
            throw CoffeeShopsRefreshError("Unable to refresh data", null)
        }
        return@async response.body?.string()
    }
}
重點只有兩點 :
lifecycleScope.async(Dispatchers.IO) {} : 在 IO 執行緒上啟動 coroutine
return@async response.body?.string()
return@async是用來指定要返回的值,因為目前還沒把 Json 字串接出來,就簡單地返回字串就好。
終於成功拉~~~
好好讀完後再寫就沒有感到很難,學習果然不能囫圇吞棗阿哈哈
